﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Management;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
using System.Xml;
using FlickrNet;

namespace Flickr2Frame
{
    public partial class Flickr2Frame : Form
    {
        ManagementEventWatcher driveWatcher;
        WqlEventQuery eventQuery;
        DateTime lastDriveWatcherEventArrived;
        BackgroundWorker frameDetection;
        Thread updateFrameThread;
        System.Drawing.Size iconSize = new System.Drawing.Size(200, 200);

        delegate void SetFormStateDelegate(FormMode mode);
        delegate void UpdateStatusLabelTextDelegate(string status, bool error);
        delegate void CalibrateProgressBarDelegate(ref ProgressBar progressBar, int step, int value, int minimum, int maximum, ProgressBarStyle style, int marqueeAnimationSpeed, RightToLeft rightToLeft);
        delegate void PerformProgressBarStepDelegate(ref ProgressBar progressBar);
        delegate void PerformButtonClickDelegate(ref Button button);
        delegate void SetLabelTextDelegate(ref Label label, string text);
        delegate void SetPictureBoxImageDelegate(ref PictureBox pictureBox, Image image, PictureBoxSizeMode sizeMode, System.Drawing.Size size);
        delegate DialogResult ShowConfirmDeleteDialogDelegate(string deleteDirectory);

        enum FormMode
        {
            Waiting,
            Ready,
            Busy,
            Scanning,
            Complete,
            Cancelling
        }

        struct F2FPhoto
        {
            public string path;
            public DateTime dateTaken;

            public class Asc : IComparer
            {
                public int Compare(object x, object y)
                {
                    return (((F2FPhoto)x).dateTaken).CompareTo(((F2FPhoto)y).dateTaken);
                }
            }

            public class Desc : IComparer
            {
                public int Compare(object x, object y)
                {
                    return (((F2FPhoto)y).dateTaken).CompareTo(((F2FPhoto)x).dateTaken);
                }
            }
        }

        public Flickr2Frame()
        {
            try
            {
                InitializeComponent();
                this.Icon = global::Flickr2Frame.Properties.Resources.Family;
                this.Text += String.Format(" ({0}.{1}.{2})", Assembly.GetExecutingAssembly().GetName().Version.Major, Assembly.GetExecutingAssembly().GetName().Version.Minor, Assembly.GetExecutingAssembly().GetName().Version.Build);
                this.Load += new EventHandler(Flickr2Frame_Load);
                this.FormClosing += new FormClosingEventHandler(Flickr2Frame_FormClosing);
                actionButton.Click += new EventHandler(actionButton_Click);
                homeLinkLabel.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.homeLinkLabel_LinkClicked);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "Flickr2Frame()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void actionButton_Click(object sender, EventArgs e)
        {
            try
            {
                switch (actionButton.Text)
                {
                    case "Select Frame":
                        StopDriveWatcher();
                        DriveSelector ds = new DriveSelector();

                        if (ds.ShowDialog() == DialogResult.OK)
                        {
                            Debug.WriteLine(ds.SelectedDriveLetter);

                            if (File.Exists(Path.Combine(ds.SelectedDriveLetter + @"\", PublicVariables.flickr2FrameXmlName)))
                            {
                                UpdateStatusLabelText("Reading Flickr2Frame configuration...", false);

                                if (ReadConfigXml(Path.Combine(ds.SelectedDriveLetter + @"\", PublicVariables.flickr2FrameXmlName)))
                                {
                                    PublicVariables.frameDriveLetter = ds.SelectedDriveLetter + @"\";
                                    SetFormState(FormMode.Ready);
                                    UpdateStatusLabelText("Ready to update frame.", false);
                                }
                                else
                                {
                                    MessageBox.Show("There was an error reading the configuration file on the frame.\r\rPlease use the \"ConfigFrame.exe\" application to ensure all values are present and correct.", "Configuration File Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                    StartDriveWatcher();
                                    UpdateStatusLabelText("Error reading Flickr2Frame configuration.", true);
                                }
                            }
                            else
                            {
                                MessageBox.Show("The selected drive does not contain a valid configuration file for Flickr2Frame.\r\rPlease create one using the \"ConfigFrame.exe\" application.", "Missing Configuration File", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                                StartDriveWatcher();
                                UpdateStatusLabelText("Selected frame is not configured.", true);
                                SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Warning, PictureBoxSizeMode.CenterImage, iconSize);
                            }
                        }

                        break;
                    case "Update Frame":
                        updateFrameThread = new Thread(new ThreadStart(UpdateFrame));
                        updateFrameThread.Start();
                        break;
                    case "Close":
                        this.Close();
                        break;
                    case "Cancel":
                        SetFormState(FormMode.Cancelling);
                        updateFrameThread.Abort();

                        while (updateFrameThread.ThreadState != System.Threading.ThreadState.Stopped)
                        {
                            Thread.Sleep(100);
                        }

                        SetFormState(FormMode.Ready);
                        UpdateStatusLabelText("Update cancelled.", true);
                        SetLabelText(ref fileStatusLabel, String.Empty);
                        CalibrateProgressBar(ref taskProgressBar, 1, 0, 0, 1, ProgressBarStyle.Continuous, PublicVariables.marqueeAnimationSpeed, RightToLeft.No);
                        CalibrateProgressBar(ref overallProgressBar, 1, 0, 0, 1, ProgressBarStyle.Continuous, PublicVariables.marqueeAnimationSpeed, RightToLeft.No);
                        SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Abort, PictureBoxSizeMode.CenterImage, iconSize);
                        break;
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "actionButton_Click()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void Flickr2Frame_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                if ((frameDetection != null) && (frameDetection.IsBusy))
                {
                    frameDetection.CancelAsync();
                }

                if ((updateFrameThread != null) && (updateFrameThread.ThreadState != System.Threading.ThreadState.Stopped))
                {
                    Debug.WriteLine("Aborting thread on form close");
                    updateFrameThread.Abort();
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "Flickr2Frame_FormClosing()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            StopDriveWatcher();
        }

        void Flickr2Frame_Load(object sender, EventArgs e)
        {
            try
            {
                lastDriveWatcherEventArrived = DateTime.Now;
                StartFrameDetectionThread();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "Flickr2Frame_Load()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void StartDriveWatcher()
        {
            try
            {
                Debug.WriteLine("StartDriveWatcher()");
                eventQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent");
                driveWatcher = new ManagementEventWatcher(eventQuery);
                driveWatcher.EventArrived += new EventArrivedEventHandler(driveWatcher_EventArrived);
                driveWatcher.Start();
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "StartDriveWatcher()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void driveWatcher_EventArrived(object sender, EventArrivedEventArgs e)
        {
            try
            {
                Debug.WriteLine("driveWatcher_EventArrived()");
                lastDriveWatcherEventArrived = DateTime.Now;
                StartFrameDetectionThread();
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "driveWatcher_EventArrived()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void StartFrameDetectionThread()
        {
            try
            {
                Debug.WriteLine("StartFrameDetectionThread()");
                SetFormState(FormMode.Scanning);
                CalibrateProgressBar(ref taskProgressBar, 1, 1, 0, 2, ProgressBarStyle.Marquee, PublicVariables.marqueeAnimationSpeed, RightToLeft.No);
                CalibrateProgressBar(ref overallProgressBar, 1, 1, 0, 2, ProgressBarStyle.Marquee, PublicVariables.marqueeAnimationSpeed, RightToLeft.Yes);
                UpdateStatusLabelText("Scanning drives for digital frames or memory cards...", false);
                SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Search, PictureBoxSizeMode.CenterImage, iconSize);

                if ((frameDetection == null) || (!frameDetection.IsBusy))
                {
                    frameDetection = new BackgroundWorker();
                    frameDetection.DoWork += new DoWorkEventHandler(frameDetection_DoWork);
                    frameDetection.RunWorkerCompleted += new RunWorkerCompletedEventHandler(frameDetection_RunWorkerCompleted);
                    frameDetection.WorkerSupportsCancellation = true;
                    frameDetection.RunWorkerAsync();
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "StartFrameDetectionThread()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void frameDetection_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                Debug.WriteLine("frameDetection_RunWorkerCompleted()");

                if (PublicVariables.frameDriveLetter == null)
                {
                    StartDriveWatcher();
                    SetFormState(FormMode.Waiting);
                }
                else
                {
                    Debug.WriteLine("Frame detected on " + PublicVariables.frameDriveLetter);
                    SetFormState(FormMode.Ready);

                    if (PublicVariables.autoStartUpdate)
                    {
                        PerformButtonClick(ref actionButton);
                    }
                    else
                    {
                        UpdateStatusLabelText("Ready to update frame.", false);
                        SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.USB, PictureBoxSizeMode.CenterImage, iconSize);
                    }
                }

                CalibrateProgressBar(ref taskProgressBar, 1, 0, 0, 1, ProgressBarStyle.Continuous, PublicVariables.marqueeAnimationSpeed, RightToLeft.No);
                CalibrateProgressBar(ref overallProgressBar, 1, 0, 0, 1, ProgressBarStyle.Continuous, PublicVariables.marqueeAnimationSpeed, RightToLeft.No);
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "frameDetection_RunWorkerCompleted()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void frameDetection_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                Debug.WriteLine("frameDetection_DoWork()");
                StopDriveWatcher();
                PublicVariables.frameDriveLetter = null;

                while (DateTime.Now.Subtract(lastDriveWatcherEventArrived).TotalMilliseconds < PublicVariables.frameDetectionTimeout)
                {
                    if (!frameDetection.CancellationPending)
                    {
                        foreach (string driveLetter in GetDriveLetters())
                        {
                            if (!frameDetection.CancellationPending)
                            {
                                if (File.Exists(Path.Combine(driveLetter, PublicVariables.flickr2FrameXmlName)))
                                {
                                    if (!frameDetection.CancellationPending)
                                    {
                                        UpdateStatusLabelText("Frame detected on " + driveLetter + ".", false);

                                        if (ReadConfigXml(Path.Combine(driveLetter, PublicVariables.flickr2FrameXmlName)))
                                        {
                                            PublicVariables.frameDriveLetter = driveLetter;
                                            return;
                                        }
                                        else
                                        {
                                            MessageBox.Show("There was an error reading the configuration file on the frame.\r\rPlease use the \"ConfigFrame.exe\" application to ensure all values are present and correct.", "Configuration File Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                            UpdateStatusLabelText("Error reading Flickr2Frame configuration.", true);
                                            SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Error, PictureBoxSizeMode.CenterImage, iconSize);
                                            return;
                                        }
                                    }
                                }
                            }
                        }
                    }

                    Thread.Sleep(100);
                }

                UpdateStatusLabelText("Please connect and power on your frame or memory card now.", false);
                SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.USB, PictureBoxSizeMode.CenterImage, iconSize);
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "frameDetection_DoWork()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void StopDriveWatcher()
        {
            try
            {
                Debug.WriteLine("StopDriveWatcher");

                if (driveWatcher != null)
                {
                    driveWatcher.Stop();
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "StopDriveWatcher()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        ArrayList GetDriveLetters()
        {
            ArrayList driveLetters = new ArrayList();

            try
            {
                ManagementObjectSearcher mos = new ManagementObjectSearcher(@"\\.\root\CIMV2", "SELECT DeviceID FROM Win32_LogicalDisk WHERE DriveType='2' OR DriveType='3'");
                ManagementObjectCollection moc = mos.Get();

                if (moc.Count > 0)
                {
                    foreach (ManagementObject mo in moc)
                    {
                        driveLetters.Add(mo.Properties["DeviceID"].Value.ToString() + @"\");
                    }
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "GetDriveLetters()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return driveLetters;
        }

        bool ReadConfigXml(string path)
        {
            Debug.WriteLine("Reading " + path);

            try
            {
                XmlDocument configXml = new XmlDocument();
                StringEncryption se = new StringEncryption();
                configXml.Load(path);
                PublicVariables.flickrSetPrefix = configXml.SelectSingleNode("configuration/flickr_set_prefix").InnerText;
                PublicVariables.photoDirectory = configXml.SelectSingleNode("configuration/photo_directory").InnerText;
                PublicVariables.frameType = StringToSupportedFrames(configXml.SelectSingleNode("configuration/frame_type").InnerText);
                PublicVariables.photoOrder = StringToPhotoOrder(configXml.SelectSingleNode("configuration/photo_order").InnerText);
                PublicVariables.photoDownloadSize = StringToPhotoSize(configXml.SelectSingleNode("configuration/photo_download_size").InnerText);
                PublicVariables.flickrApiKey = se.Decrypt(configXml.SelectSingleNode("configuration/flickr_api_key").InnerText, "charlton");
                PublicVariables.flickrAuthenticationToken = se.Decrypt(configXml.SelectSingleNode("configuration/flickr_authentication_token").InnerText, "charlton");
                PublicVariables.flickrSharedSecret = se.Decrypt(configXml.SelectSingleNode("configuration/flickr_shared_secret").InnerText, "charlton");
                PublicVariables.flickrUserId = se.Decrypt(configXml.SelectSingleNode("configuration/flickr_user_id").InnerText, "charlton");
                return true;
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "ReadConfigXml()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return false;
        }

        PublicVariables.SupportedFrames StringToSupportedFrames(string frameType)
        {
            try
            {
                switch (frameType.ToUpper())
                {
                    case "PHILIPS01":
                        return PublicVariables.SupportedFrames.Philips01;
                    case "PHILIPS02":
                        return PublicVariables.SupportedFrames.Philips02;
                    default:
                        return PublicVariables.SupportedFrames.GenericUSB01;
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "StringToSupportedFrames()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return PublicVariables.SupportedFrames.GenericUSB01;
        }

        PublicVariables.PhotoOrder StringToPhotoOrder(string order)
        {
            try
            {
                switch (order.ToUpper())
                {
                    case "RANDOM":
                        return PublicVariables.PhotoOrder.Random;
                    default:
                        return PublicVariables.PhotoOrder.Sequential;
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "StringToPhotoOrder()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return PublicVariables.PhotoOrder.Sequential;
        }

        PublicVariables.PhotoSize StringToPhotoSize(string photoSize)
        {
            try
            {
                switch (photoSize.ToUpper())
                {
                    case "SMALL":
                        return PublicVariables.PhotoSize.Small;
                    case "MEDIUM":
                        return PublicVariables.PhotoSize.Medium;
                    case "LARGE":
                        return PublicVariables.PhotoSize.Large;
                    default:
                        return PublicVariables.PhotoSize.Original;
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "StringToPhotoSize()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return PublicVariables.PhotoSize.Original;
        }

        void SetFormState(FormMode mode)
        {
            try
            {
                if (InvokeRequired)
                {
                    Invoke(new SetFormStateDelegate(SetFormState), new object[] { mode });
                }
                else
                {
                    switch (mode)
                    {
                        case FormMode.Waiting:
                            actionButton.Enabled = true;
                            actionButton.Text = "Select Frame";
                            break;
                        case FormMode.Ready:
                            actionButton.Enabled = true;
                            actionButton.Text = "Update Frame";
                            break;
                        case FormMode.Busy:
                            actionButton.Enabled = true;
                            actionButton.Text = "Cancel";
                            break;
                        case FormMode.Scanning:
                            actionButton.Enabled = false;
                            actionButton.Text = String.Empty;
                            break;
                        case FormMode.Complete:
                            actionButton.Enabled = true;
                            actionButton.Text = "Close";
                            break;
                        case FormMode.Cancelling:
                            actionButton.Enabled = false;
                            actionButton.Text = "Cancelling";
                            break;
                    }
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "SetFormState()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void UpdateStatusLabelText(string status, bool error)
        {
            try
            {
                if (InvokeRequired)
                {
                    Invoke(new UpdateStatusLabelTextDelegate(UpdateStatusLabelText), new object[] { status, error });
                }
                else
                {
                    statusLabel.Text = status;

                    if (error)
                    {
                        statusLabel.ForeColor = Color.Red;
                    }
                    else
                    {
                        statusLabel.ForeColor = Color.Blue;
                    }
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "UpdateStatusLabelText()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void UpdateFrame()
        {
            try
            {
                SetFormState(FormMode.Busy);
                CalibrateProgressBar(ref taskProgressBar, 1, 0, 0, 1, ProgressBarStyle.Marquee, PublicVariables.marqueeAnimationSpeed, RightToLeft.No);
                CalibrateProgressBar(ref overallProgressBar, 1, 0, 0, (PublicVariables.overallTasks + PublicVariables.additionalTasks), ProgressBarStyle.Continuous, PublicVariables.marqueeAnimationSpeed, RightToLeft.No);
                string frameTargetPath = Path.Combine(PublicVariables.frameDriveLetter, PublicVariables.photoDirectory);
                UpdateStatusLabelText("Updating application shortcuts...", false);
                PerformProgressBarStep(ref overallProgressBar);
                UpdateStartMenuShortcut();
                UpdateDesktopShortcut();
                UpdateStatusLabelText("Verifying target path on frame...", false);
                PerformProgressBarStep(ref overallProgressBar);

                if (Directory.Exists(frameTargetPath))
                {
                    UpdateStatusLabelText("Creating temporary download directory...", false);
                    PerformProgressBarStep(ref overallProgressBar);
                    DeleteTempDownloadDirectory();

                    if (CreateTempDownloadDirectory())
                    {
                        Flickr flickr = null;
                        UpdateStatusLabelText("Authenticating with Flickr...", false);
                        SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Flickr, PictureBoxSizeMode.CenterImage, iconSize);
                        PerformProgressBarStep(ref overallProgressBar);

                        if (AuthenticateWithFlickr(ref flickr))
                        {
                            if (PublicVariables.flushCache)
                            {
                                UpdateStatusLabelText("Flushing FlickrNET download cache...", false);
                                SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Delete, PictureBoxSizeMode.CenterImage, iconSize);
                                PerformProgressBarStep(ref overallProgressBar);
                                Flickr.FlushCache();
                            }

                            ArrayList photosetIds = new ArrayList();
                            UpdateStatusLabelText("Getting Sets for \"" + PublicVariables.flickrSetPrefix + "\" from Flickr...", false);
                            SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Flickr, PictureBoxSizeMode.CenterImage, iconSize);
                            PerformProgressBarStep(ref overallProgressBar);

                            if (GetMyPhotosets(ref flickr, ref photosetIds))
                            {
                                if (photosetIds.Count > 0)
                                {
                                    int availablePhotos = 0;
                                    UpdateStatusLabelText("Counting available photos for \"" + PublicVariables.flickrSetPrefix + "\" from Flickr...", false);
                                    SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Flickr, PictureBoxSizeMode.CenterImage, iconSize);
                                    PerformProgressBarStep(ref overallProgressBar);

                                    if (GetAvailablePhotosFromSets(ref flickr, ref photosetIds, ref availablePhotos))
                                    {
                                        if (availablePhotos > 0)
                                        {
                                            Flickr.CacheDisabled = PublicVariables.flickrNetCacheDisabled;
                                            Flickr.CacheSizeLimit = PublicVariables.flickrNetCacheSizeLimit;
                                            Flickr.CacheTimeout = PublicVariables.flickrNetCacheTimeoutSeconds;
                                            CalibrateProgressBar(ref taskProgressBar, 1, 0, 0, availablePhotos, ProgressBarStyle.Continuous, PublicVariables.marqueeAnimationSpeed, RightToLeft.No);
                                            DownloadPhotos(ref flickr, ref photosetIds, availablePhotos);
                                            ArrayList downloadedPhotos = EnumerateFilesInDirectory(PublicVariables.tempDirPath);

                                            if (downloadedPhotos.Count > 0)
                                            {
                                                if (DeletePhotosOnFrame())
                                                {
                                                    UpdateStatusLabelText("Copying new photos to frame...", false);
                                                    SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Copy, PictureBoxSizeMode.CenterImage, iconSize);
                                                    PerformProgressBarStep(ref overallProgressBar);
                                                    SetFrameSpecificValues();
                                                    CopyPhotosToFrame(ref downloadedPhotos);
                                                    UpdateStatusLabelText("Performing frame type specific tasks...", false);
                                                    PerformProgressBarStep(ref overallProgressBar);
                                                    PerformFrameSpecificTasks();
                                                    UpdateStatusLabelText("Deleting temporary download directory...", false);
                                                    SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Delete, PictureBoxSizeMode.CenterImage, iconSize);
                                                    PerformProgressBarStep(ref overallProgressBar);
                                                    DeleteTempDownloadDirectory();
                                                    SetFormState(FormMode.Complete);
                                                    UpdateStatusLabelText("Update complete. You may now disconnect the frame.", false);
                                                    SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Complete, PictureBoxSizeMode.CenterImage, iconSize);
                                                    return;
                                                }
                                                else
                                                {
                                                    UpdateStatusLabelText("Update cannot continue unless existing photos are deleted on frame.", true);
                                                    SetLabelText(ref fileStatusLabel, String.Empty);
                                                    SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Warning, PictureBoxSizeMode.CenterImage, iconSize);
                                                }
                                            }
                                            else
                                            {
                                                UpdateStatusLabelText("No photos were downloaded from Flickr.", true);
                                                SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Warning, PictureBoxSizeMode.CenterImage, iconSize);
                                            }
                                        }
                                        else
                                        {
                                            UpdateStatusLabelText("There are no photos available for \"" + PublicVariables.flickrSetPrefix + "\" on Flickr.", true);
                                            SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Warning, PictureBoxSizeMode.CenterImage, iconSize);
                                        }
                                    }
                                    else
                                    {
                                        UpdateStatusLabelText("Error counting photos on Flickr.", true);
                                        SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Error, PictureBoxSizeMode.CenterImage, iconSize);
                                    }
                                }
                                else
                                {
                                    UpdateStatusLabelText("No Sets on Flickr for \"" + PublicVariables.flickrSetPrefix + "\".", true);
                                    SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Warning, PictureBoxSizeMode.CenterImage, iconSize);
                                }
                            }
                            else
                            {
                                UpdateStatusLabelText("Error querying Photo Set information on Flickr.", true);
                                SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Error, PictureBoxSizeMode.CenterImage, iconSize);
                            }
                        }
                        else
                        {
                            UpdateStatusLabelText("Error authenticating with Flickr.", true);
                            SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Error, PictureBoxSizeMode.CenterImage, iconSize);
                        }
                    }
                    else
                    {
                        UpdateStatusLabelText("Error creating temporary download directory.", true);
                        SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Error, PictureBoxSizeMode.CenterImage, iconSize);
                    }
                }
                else
                {
                    UpdateStatusLabelText("Could not locate \"" + frameTargetPath + "\".", true);
                    SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Error, PictureBoxSizeMode.CenterImage, iconSize);
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "UpdateFrame()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            SetFormState(FormMode.Ready);
            CalibrateProgressBar(ref taskProgressBar, 1, 0, 0, 1, ProgressBarStyle.Continuous, PublicVariables.marqueeAnimationSpeed, RightToLeft.No);
            CalibrateProgressBar(ref overallProgressBar, 1, 0, 0, 1, ProgressBarStyle.Continuous, PublicVariables.marqueeAnimationSpeed, RightToLeft.No);
        }

        void UpdateStartMenuShortcut()
        {
            try
            {
                if (PublicVariables.createStartMenuShortcut)
                {
                    IWshRuntimeLibrary.WshShell wshShell = new IWshRuntimeLibrary.WshShell();
                    IWshRuntimeLibrary.IWshShortcut shortcut = (IWshRuntimeLibrary.IWshShortcut)wshShell.CreateShortcut(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Programs), "Flickr2Frame.lnk"));
                    shortcut.TargetPath = Environment.GetCommandLineArgs()[0];
                    shortcut.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory;
                    shortcut.Description = "http://flickr2frame.codeplex.com/";
                    shortcut.Save();
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "UpdateStartMenuShortcut()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void UpdateDesktopShortcut()
        {
            try
            {
                if (PublicVariables.createDesktopShortcut)
                {
                    IWshRuntimeLibrary.WshShell wshShell = new IWshRuntimeLibrary.WshShell();
                    IWshRuntimeLibrary.IWshShortcut shortcut = (IWshRuntimeLibrary.IWshShortcut)wshShell.CreateShortcut(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Flickr2Frame.lnk"));
                    shortcut.TargetPath = Environment.GetCommandLineArgs()[0];
                    shortcut.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory;
                    shortcut.Description = "http://flickr2frame.codeplex.com/";
                    shortcut.Save();
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "UpdateDesktopShortcut()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void DownloadPhotos(ref Flickr flickr, ref ArrayList photosetIds, int totalPhotos)
        {
            try
            {
                int downloaded = 1;

                foreach (string id in photosetIds)
                {
                    string setTitle = flickr.PhotosetsGetInfo(id).Title.Substring(String.Format("{0}{1}{2}{1}", PublicVariables.setNamePrefix, PublicVariables.setNameDelimiter, PublicVariables.flickrSetPrefix).Length);
                    UpdateStatusLabelText("Downloading photos from\r\"" + setTitle + "\"...", false);
                    string downloadDirectory = Path.Combine(PublicVariables.tempDirPath, setTitle);

                    if (!Directory.Exists(downloadDirectory))
                    {
                        Directory.CreateDirectory(downloadDirectory);
                    }

                    int pageNumber = 1;

                    try
                    {
                        while (true)
                        {
                            foreach (Photo photo in flickr.PhotosetsGetPhotos(id, pageNumber, PublicVariables.photosPerPage).PhotoCollection)
                            {
                                PerformProgressBarStep(ref taskProgressBar);
                                string photoTitle = photo.Title;

                                if (File.Exists(Path.Combine(downloadDirectory, photoTitle + ".jpg")))
                                {
                                    string originalTitle = photoTitle;
                                    int renameSeries = 1;

                                    while (File.Exists(Path.Combine(downloadDirectory, photoTitle + ".jpg")))
                                    {
                                        photoTitle = String.Format("{0} ({1})", originalTitle, renameSeries.ToString());
                                        renameSeries += 1;
                                    }
                                }

                                Debug.WriteLine(photoTitle);
                                SetLabelText(ref fileStatusLabel, String.Format("{0} of {1}", downloaded, totalPhotos));
                                Image downloadedImage = null;

                                switch (PublicVariables.photoDownloadSize)
                                {
                                    case PublicVariables.PhotoSize.Small:
                                        downloadedImage = Image.FromStream(flickr.DownloadPicture(photo.SmallUrl));
                                        break;
                                    case PublicVariables.PhotoSize.Medium:
                                        downloadedImage = Image.FromStream(flickr.DownloadPicture(photo.MediumUrl));
                                        break;
                                    case PublicVariables.PhotoSize.Large:
                                        downloadedImage = Image.FromStream(flickr.DownloadPicture(photo.LargeUrl));
                                        break;
                                    case PublicVariables.PhotoSize.Original:
                                        downloadedImage = Image.FromStream(flickr.DownloadPicture(photo.OriginalUrl));
                                        break;
                                }

                                downloadedImage.Save(Path.Combine(downloadDirectory, photoTitle + ".jpg"), System.Drawing.Imaging.ImageFormat.Jpeg);
                                SetPictureBoxImage(ref thumbnailPictureBox, downloadedImage, PictureBoxSizeMode.Zoom, downloadedImage.Size);
                                downloaded += 1;
                            }

                            pageNumber += 1;
                        }
                    }
                    catch
                    {
                        break;
                    }
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (InvalidOperationException ioEx)
            {
                MessageBox.Show(ioEx.Message + "\r\rPlease make sure you have selected the correct download size applicable to your Flickr account (Free or Pro).", "Invalid Operation", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "DownloadPhotos()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void PerformFrameSpecificTasks()
        {
            try
            {
                switch (PublicVariables.frameType)
                {
                    case PublicVariables.SupportedFrames.Philips02:
                        CreateLONGNAMEFiles();
                        break;
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "PerformFrameSpecificTasks()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void CreateLONGNAMEFiles()
        {
            try
            {
                string frameTargetPath = Path.Combine(PublicVariables.frameDriveLetter, PublicVariables.photoDirectory);
                int albumFolderSuffix = 0;

                foreach (string directory in Directory.GetDirectories(frameTargetPath))
                {
                    StreamWriter longnameFile = new StreamWriter(Path.Combine(directory, "LONGNAME"));
                    longnameFile.Write(CalculateLONGNAMEText(new DirectoryInfo(directory).Name));
                    longnameFile.Close();
                    File.SetAttributes(Path.Combine(directory, "LONGNAME"), FileAttributes.Hidden);
                    Directory.Move(directory, Path.Combine(new DirectoryInfo(directory).Parent.FullName, String.Format("{0}{1}", albumFolderSuffix.ToString().PadLeft(3, Convert.ToChar("0")), "ALBUM")));
                    albumFolderSuffix++;
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "CreateLONGNAMEFiles()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void CopyPhotosToFrame(ref ArrayList downloadedPhotos)
        {
            try
            {
                CalibrateProgressBar(ref taskProgressBar, 1, 0, 0, downloadedPhotos.Count, ProgressBarStyle.Continuous, PublicVariables.marqueeAnimationSpeed, RightToLeft.No);
                int progressCount = 1;

                if (PublicVariables.photoOrder == PublicVariables.PhotoOrder.Random)
                {
                    ShuffleInPlace(ref downloadedPhotos);
                }
                else
                {
                    downloadedPhotos.Sort();
                }

                if ((PublicVariables.latestPhotoCount > 0) && (PublicVariables.latestPhotoCount < downloadedPhotos.Count))
                {
                    ArrayList latestPhotos = new ArrayList();

                    foreach (string photo in downloadedPhotos)
                    {
                        F2FPhoto f2fPhoto = new F2FPhoto();
                        f2fPhoto.path = photo;
                        f2fPhoto.dateTaken = DateTaken(Image.FromFile(photo));
                        latestPhotos.Add(f2fPhoto);
                    }

                    latestPhotos.Sort(new F2FPhoto.Desc());

                    for (int i = 0; i < PublicVariables.latestPhotoCount; i++)
                    {
                        Debug.WriteLine(String.Format("{0}\t{1}", i, ((F2FPhoto)latestPhotos[i]).path));
                        downloadedPhotos.Remove(((F2FPhoto)latestPhotos[i]).path);
                        downloadedPhotos.Insert(i, ((F2FPhoto)latestPhotos[i]).path);
                    }
                }

                for (int i = 0; i < downloadedPhotos.Count; i++)
                {
                    PerformProgressBarStep(ref taskProgressBar);
                    string targetDirectory = null;
                    string frameTargetPath = Path.Combine(PublicVariables.frameDriveLetter, PublicVariables.photoDirectory);

                    if (PublicVariables.copyAllToRoot)
                    {
                        targetDirectory = frameTargetPath;
                    }
                    else
                    {
                        targetDirectory = Path.Combine(frameTargetPath, new DirectoryInfo(downloadedPhotos[i].ToString()).Parent.Name);
                    }

                    if ((new DriveInfo(PublicVariables.frameDriveLetter).AvailableFreeSpace - PublicVariables.leaveFreeOnFrame) > (new FileInfo(downloadedPhotos[i].ToString()).Length))
                    {
                        if (!Directory.Exists(targetDirectory))
                        {
                            Directory.CreateDirectory(targetDirectory);
                        }

                        string fileName = null;

                        if (PublicVariables.autoNamePhotos)
                        {
                            fileName = String.Format("{0}{1}{2}", PublicVariables.photoNamePrefix, (Directory.GetFiles(targetDirectory).Length + 1).ToString().PadLeft(PublicVariables.photoNameSuffixDigits, Convert.ToChar("0")), new FileInfo(downloadedPhotos[i].ToString()).Extension);
                        }
                        else
                        {
                            fileName = new FileInfo(downloadedPhotos[i].ToString()).Name;
                        }

                        SetLabelText(ref fileStatusLabel, String.Format("{0} of {1}", progressCount.ToString(), downloadedPhotos.Count));
                        File.Copy(downloadedPhotos[i].ToString(), Path.Combine(targetDirectory, fileName), true);
                        progressCount++;
                    }
                }

                SetLabelText(ref fileStatusLabel, String.Empty);
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "CopyPhotosToFrame()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        DialogResult ShowConfirmDeleteDialog(string deleteDirectory)
        {
            try
            {
                if (InvokeRequired)
                {
                    return (DialogResult)Invoke(new ShowConfirmDeleteDialogDelegate(ShowConfirmDeleteDialog), new object[] { deleteDirectory });
                }
                else
                {
                    ConfirmDelete cd = new ConfirmDelete(deleteDirectory);
                    DialogResult delete = cd.ShowDialog();

                    if ((delete == DialogResult.OK) && (cd.HideFutureWarnings))
                    {
                        WriteToLocalAppXml("hide_delete_warning", "true");
                    }

                    return delete;
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "ShowConfirmDeleteDialog()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return DialogResult.Cancel;
        }

        bool DeletePhotosOnFrame()
        {
            try
            {
                if (ShowDeleteWarning())
                {
                    UpdateStatusLabelText("Waiting for deletion confirmation...", false);
                    SetLabelText(ref fileStatusLabel, String.Empty);
                    SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Warning, PictureBoxSizeMode.CenterImage, iconSize);
                    CalibrateProgressBar(ref taskProgressBar, 1, 0, 0, 1, ProgressBarStyle.Continuous, PublicVariables.marqueeAnimationSpeed, RightToLeft.No);

                    if (ShowConfirmDeleteDialog(PublicVariables.frameDriveLetter + PublicVariables.photoDirectory) != DialogResult.OK)
                    {
                        return false;
                    }
                }

                UpdateStatusLabelText("Deleting current photos on frame...", false);
                SetPictureBoxImage(ref thumbnailPictureBox, global::Flickr2Frame.Properties.Resources.Delete, PictureBoxSizeMode.CenterImage, iconSize);
                PerformProgressBarStep(ref overallProgressBar);
                string frameTargetPath = Path.Combine(PublicVariables.frameDriveLetter, PublicVariables.photoDirectory);
                ArrayList photosOnFrame = EnumerateFilesInDirectory(frameTargetPath);
                CalibrateProgressBar(ref taskProgressBar, 1, 0, 0, photosOnFrame.Count, ProgressBarStyle.Continuous, PublicVariables.marqueeAnimationSpeed, RightToLeft.No);
                int progressCount = 1;

                foreach (string photo in photosOnFrame)
                {
                    SetLabelText(ref fileStatusLabel, String.Format("{0} of {1}", progressCount.ToString(), photosOnFrame.Count));
                    PerformProgressBarStep(ref taskProgressBar);

                    Debug.WriteLine(photo);
                    File.Delete(photo);
                    progressCount++;
                }

                foreach (string directory in Directory.GetDirectories(frameTargetPath))
                {
                    Directory.Delete(directory, true);
                }

                SetLabelText(ref fileStatusLabel, String.Empty);
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "DeletePhotosOnFrame()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return true;
        }

        void SetFrameSpecificValues()
        {
            try
            {
                switch (PublicVariables.frameType)
                {
                    case PublicVariables.SupportedFrames.Philips01:
                        PublicVariables.autoNamePhotos = true;
                        PublicVariables.photoNamePrefix = "Phi_";
                        PublicVariables.photoNameSuffixDigits = 4;
                        PublicVariables.copyAllToRoot = true;
                        PublicVariables.leaveFreeOnFrame = 256;
                        PublicVariables.photoDirectory = @"DCIM\100FRAME";
                        break;
                    case PublicVariables.SupportedFrames.Philips02:
                        PublicVariables.autoNamePhotos = true;
                        PublicVariables.photoNamePrefix = "Phi_";
                        PublicVariables.photoNameSuffixDigits = 4;
                        PublicVariables.copyAllToRoot = false;
                        PublicVariables.leaveFreeOnFrame = 256;
                        PublicVariables.photoDirectory = "ALBUM";
                        break;
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "SetFrameSpecificValues()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        bool GetAvailablePhotosFromSets(ref Flickr flickr, ref ArrayList photosetIds, ref int availablePhotoCount)
        {
            try
            {
                foreach (string photosetId in photosetIds)
                {
                    int pageNumber = 1;

                    try
                    {
                        while (true)
                        {
                            availablePhotoCount += flickr.PhotosetsGetPhotos(photosetId, pageNumber, PublicVariables.photosPerPage).PhotoCollection.Length;
                            pageNumber += 1;
                            Debug.WriteLine(availablePhotoCount);
                        }
                    }
                    catch
                    {
                        break;
                    }
                }

                return true;
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "GetAvailablePhotosFromSets()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return false;
        }

        bool GetMyPhotosets(ref Flickr flickr, ref ArrayList photosetIds)
        {
            try
            {
                foreach (Photoset set in flickr.PhotosetsGetList(PublicVariables.flickrUserId).PhotosetCollection)
                {
                    Debug.WriteLine(set.Title);

                    if (set.Title.ToUpper().StartsWith(String.Format("{0}{1}{2}{1}", PublicVariables.setNamePrefix, PublicVariables.setNameDelimiter, PublicVariables.flickrSetPrefix).ToUpper()))
                    {
                        photosetIds.Add(set.PhotosetId);
                    }
                }

                return true;
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "GetMyPhotosets()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return false;
        }

        bool AuthenticateWithFlickr(ref Flickr flickr)
        {
            try
            {
                flickr = new Flickr(PublicVariables.flickrApiKey, PublicVariables.flickrSharedSecret, PublicVariables.flickrAuthenticationToken);
                return flickr.IsAuthenticated;
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "AuthenticateWithFlickr()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return false;
        }

        bool CreateTempDownloadDirectory()
        {
            try
            {
                if (!Directory.Exists(PublicVariables.tempDirPath))
                {
                    Directory.CreateDirectory(PublicVariables.tempDirPath);
                }

                return true;
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "CreateTempDownloadDirectory()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return false;
        }

        void DeleteTempDownloadDirectory()
        {
            try
            {
                if (Directory.Exists(PublicVariables.tempDirPath))
                {
                    Directory.Delete(PublicVariables.tempDirPath, true);
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "DeleteTempDownloadDirectory()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void ShuffleInPlace(ref ArrayList source)
        {
            try
            {
                Random rnd = new Random();

                for (int i = source.Count - 1; i > 0; --i)
                {
                    int position = rnd.Next(i);
                    object temp = source[i];
                    source[i] = source[position];
                    source[position] = temp;
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "ShuffleInPlace()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void CalibrateProgressBar(ref ProgressBar progressBar, int step, int value, int minimum, int maximum, ProgressBarStyle style, int marqueeAnimationSpeed, RightToLeft rightToLeft)
        {
            try
            {
                if (InvokeRequired)
                {
                    Invoke(new CalibrateProgressBarDelegate(CalibrateProgressBar), new object[] { progressBar, step, value, minimum, maximum, style, marqueeAnimationSpeed, rightToLeft });
                }
                else
                {
                    progressBar.Value = value;
                    progressBar.Step = step;
                    progressBar.Minimum = minimum;
                    progressBar.Maximum = maximum;
                    progressBar.Style = style;
                    progressBar.MarqueeAnimationSpeed = marqueeAnimationSpeed;
                    progressBar.RightToLeft = rightToLeft;
                    progressBar.RightToLeftLayout = (rightToLeft == RightToLeft.Yes);
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "CalibrateProgressBar()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void PerformProgressBarStep(ref ProgressBar progressBar)
        {
            try
            {
                if (InvokeRequired)
                {
                    Invoke(new PerformProgressBarStepDelegate(PerformProgressBarStep), new object[] { progressBar });
                }
                else
                {
                    progressBar.PerformStep();
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "PerformProgressBarStep()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void PerformButtonClick(ref Button button)
        {
            try
            {
                if (InvokeRequired)
                {
                    Invoke(new PerformButtonClickDelegate(PerformButtonClick), new object[] { button });
                }
                else
                {
                    button.PerformClick();
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "PerformButtonClick()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        public string CalculateLONGNAMEText(string albumName)
        {
            try
            {
                const int maxAlbumLength = 18;

                int longnameNumber = 800;
                string posCharOrder = "ABCDEFGHIJKLMNOPQRSTUVWXYZ####_#abcdefghijklmnopqrstuvwxyz";
                string negCharOrder = "#################.#,##########!";
                string formattedAlbumName = String.Empty;

                for (int charCount = 0; charCount <= (albumName.Trim().Length - 1); charCount++)
                {
                    if ((!Char.IsNumber(Convert.ToChar(albumName.Substring(charCount, 1)))) && (!(albumName.Substring(charCount, 1) == " ")) && (((posCharOrder.IndexOf(albumName.Substring(charCount, 1)) == -1) && (negCharOrder.IndexOf(albumName.Substring(charCount, 1)) == -1)) || (albumName.Substring(charCount, 1) == "#")))
                    {
                        formattedAlbumName += "_";
                    }
                    else
                    {
                        formattedAlbumName += albumName.Substring(charCount, 1);
                    }
                }

                if (formattedAlbumName.Length > maxAlbumLength)
                {
                    formattedAlbumName = formattedAlbumName.Substring(0, maxAlbumLength - 1);
                }

                for (int charCount = 0; charCount <= (formattedAlbumName.Trim().Length - 1); charCount++)
                {
                    if (posCharOrder.IndexOf(formattedAlbumName.Substring(charCount, 1)) > -1)
                    {
                        longnameNumber += (posCharOrder.IndexOf(formattedAlbumName.Substring(charCount, 1), StringComparison.CurrentCulture) + 1);
                    }
                }

                for (int charCount = 0; charCount <= (formattedAlbumName.Trim().Length - 1); charCount++)
                {
                    if (negCharOrder.IndexOf(formattedAlbumName.Substring(charCount, 1)) > -1)
                    {
                        longnameNumber += (0 - (negCharOrder.IndexOf(formattedAlbumName.Substring(charCount, 1), StringComparison.CurrentCulture) + 1));
                    }
                }

                if (formattedAlbumName.Trim().Length > 1)
                {
                    for (int charCount = 1; charCount <= (formattedAlbumName.Trim().Length - 1); charCount++)
                    {
                        if (Char.IsNumber(Convert.ToChar(formattedAlbumName.Substring(charCount, 1))))
                        {
                            longnameNumber += (Convert.ToInt16(formattedAlbumName.Substring(charCount, 1)) + 16);
                        }
                        else if (formattedAlbumName.Substring(charCount, 1) == " ")
                        {
                            //Do nothing for spaces
                        }
                        else
                        {
                            longnameNumber += 32;
                        }
                    }
                }

                return formattedAlbumName.PadRight(24) + longnameNumber.ToString().PadLeft(4, Convert.ToChar("0"));
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "CalculateLONGNAMEText()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return null;
        }

        ArrayList EnumerateFilesInDirectory(string directory)
        {
            ArrayList files = new ArrayList();

            try
            {

                if (Directory.Exists(directory))
                {
                    if (Directory.GetFiles(directory).Length > 0)
                    {
                        foreach (string file in Directory.GetFiles(directory))
                        {
                            files.Add(file);
                        }
                    }

                    if (Directory.GetDirectories(directory).Length > 0)
                    {
                        foreach (string subDirectory in Directory.GetDirectories(directory))
                        {
                            files.AddRange(EnumerateFilesInDirectory(subDirectory));
                        }
                    }
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "EnumerateFilesInDirectory()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return files;
        }

        void SetLabelText(ref Label label, string text)
        {
            try
            {
                if (InvokeRequired)
                {
                    Invoke(new SetLabelTextDelegate(SetLabelText), new object[] { label, text });
                }
                else
                {
                    label.Text = text;
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "SetLabelText()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void SetPictureBoxImage(ref PictureBox pictureBox, Image image, PictureBoxSizeMode sizeMode, System.Drawing.Size size)
        {
            try
            {
                if (InvokeRequired)
                {
                    Invoke(new SetPictureBoxImageDelegate(SetPictureBoxImage), new object[] { pictureBox, image, sizeMode, size });
                }
                else
                {
                    pictureBox.SizeMode = sizeMode;
                    pictureBox.Image = new Bitmap(image, size);
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "SetPictureBoxImage()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void homeLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            try
            {
                Process p = new Process();
                p.StartInfo.FileName = "http://flickr2frame.codeplex.com/";
                p.Start();
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "homeLinkLabel_LinkClicked()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        bool ShowDeleteWarning()
        {
            try
            {
                if (File.Exists(Path.Combine(PublicVariables.localAppDirPath, PublicVariables.localAppXmlName)))
                {
                    XmlDocument appXml = new XmlDocument();
                    appXml.Load(Path.Combine(PublicVariables.localAppDirPath, PublicVariables.localAppXmlName));
                    return !Convert.ToBoolean(appXml.SelectSingleNode("flickr2frame/hide_delete_warning").InnerText);
                }
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "ShowDeleteWarning()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return true;
        }

        void CreateLocalAppXmlFile()
        {
            try
            {
                if (!Directory.Exists(PublicVariables.localAppDirPath))
                {
                    Directory.CreateDirectory(PublicVariables.localAppDirPath);
                }

                XmlDocument appXml = new XmlDocument();
                appXml.LoadXml("<flickr2frame />");
                appXml.Save(Path.Combine(PublicVariables.localAppDirPath, PublicVariables.localAppXmlName));
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "CreateLocalAppXmlFile()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void WriteToLocalAppXml(string nodeName, string value)
        {
            try
            {
                if (!File.Exists(Path.Combine(PublicVariables.localAppDirPath, PublicVariables.localAppXmlName)))
                {
                    CreateLocalAppXmlFile();
                }

                XmlDocument appXml = new XmlDocument();
                XmlNode node;
                appXml.Load(Path.Combine(PublicVariables.localAppDirPath, PublicVariables.localAppXmlName));

                if (appXml.SelectSingleNode(String.Format("flickr2frame/{0}", value)) == null)
                {
                    node = appXml.CreateElement(nodeName);
                    appXml.DocumentElement.AppendChild(node);
                }
                else
                {
                    node = appXml.SelectSingleNode(String.Format("flickr2frame/{0}", value));
                }

                node.InnerText = value;
                appXml.Save(Path.Combine(PublicVariables.localAppDirPath, PublicVariables.localAppXmlName));
            }
            catch (ThreadAbortException threadAbortEx)
            {
                Debug.WriteLine(threadAbortEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + PublicVariables.additionalExceptionBlurb, "WriteToLocalAppXml()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        public static DateTime DateTaken(Image getImage)
        {
            try
            {
                const int DateTakenValue = 0x9003; //36867;
                string dateTakenTag = System.Text.Encoding.ASCII.GetString(getImage.GetPropertyItem(DateTakenValue).Value);
                string[] parts = dateTakenTag.Split(':', ' ');
                int year = int.Parse(parts[0]);
                int month = int.Parse(parts[1]);
                int day = int.Parse(parts[2]);
                int hour = int.Parse(parts[3]);
                int minute = int.Parse(parts[4]);
                int second = int.Parse(parts[5]);
                return new DateTime(year, month, day, hour, minute, second);
            }
            catch
            {
            }

            return DateTime.MinValue;
        }
    }
}
